package com.xiumu.common.core.utils;

import org.apache.commons.lang3.time.StopWatch;

import java.util.ArrayList;
import java.util.List;

/**
 * 计时器
 */
public class StopWatchUtil {

    /**
     * 计时器增强
     */
    private static class Watch {
        /**
         * 存放每一阶段的耗时
         */
        public final List<Long> executeTimeList = new ArrayList<>();
        /**
         * 计时器
         */
        public final StopWatch stopWatch = StopWatch.create();

        /**
         * 获取计时时间保存下来并重新开始计时
         * @return
         */
        public Long getTimeAndStart(){
            long time = stopWatch.getTime();
            stopWatch.reset();
            executeTimeList.add(time);
            stopWatch.start();
            return time;
        }
    }

    /**
     * 存储计时
     */
    private static final ThreadLocal<Watch> WATCH_THREAD_LOCAL = new InheritableThreadLocal<Watch>();

    /**
     * 开始计时
     */
    public static void start(){
        Watch watch = WATCH_THREAD_LOCAL.get();
        if (watch == null){
            watch = new Watch();
            watch.stopWatch.start();
            WATCH_THREAD_LOCAL.set(watch);
        }else if (watch.stopWatch.isStopped()){
            watch.stopWatch.start();
        }
    }
    /**
     * 结束计时
     */
    public static void stop(){
        Watch watch = WATCH_THREAD_LOCAL.get();
        if (watch != null){
            watch.stopWatch.stop();
            WATCH_THREAD_LOCAL.remove();
        }
    }

    /**
     * 获取与上一次 getTime 间隔的时间
     * 即 保留一次执行时间，重置计时器，再开始
     */
    public static Long getTime(){
        Watch watch = WATCH_THREAD_LOCAL.get();
        if (watch != null){
            return watch.getTimeAndStart();
        }
        return 0L;
    }

    /**
     * 获取与上一次 getTime 间隔的时间, 并停止计时
     * 即 保留一次执行时间，重置计时器，再开始
     */
    public static Long getTimeAndStop(){
        Watch watch = WATCH_THREAD_LOCAL.get();
        if (watch != null){
            Long time = watch.getTimeAndStart();
            stop();
            return time;
        }
        return 0L;
    }

    /**
     * 获取计时器从开始到现在的整个时间
     */
    public static Long getGlobalTime(){
        Watch watch = WATCH_THREAD_LOCAL.get();
        if (watch != null){
            watch.getTimeAndStart();
            return watch.executeTimeList.stream().reduce(Long::sum).orElse(0L);
        }
        return 0L;
    }

    /**
     * 获取计时器从开始到现在的整个时间并停止计时
     */
    public static Long getGlobalTimeAndStop(){
        Watch watch = WATCH_THREAD_LOCAL.get();
        if (watch != null){
            watch.getTimeAndStart();
            Long time = watch.executeTimeList.stream().reduce(Long::sum).orElse(0L);
            stop();
            return time;
        }
        return 0L;
    }

}
